home *** CD-ROM | disk | FTP | other *** search
Text File | 1997-03-05 | 29.3 KB | 770 lines | [TEXT/PJMM] |
- { CelsiusCDEFStub }
- {}
- { Stub control definition for the CelsiusCDEF control }
- {}
- { Copyright © Sebastiano Pilla 1996 }
- { <mailto:case@tvol.it> }
-
- { Control definition procedure for implementing a progress bar similar to that used by the Finder. }
- { Additionally, by setting the appropriate variation codes, it is possible to: }
- { 1) obtain a 'barber pole' effect (indefinite progress bar) }
- { 2) ignore the colors in any control color table (either default or custom) and use always the standard colors }
- { 3) never dim the control, thus drawing always in the 'active' state }
- { 4) draw a 3D-like inset effect }
-
- { Credits }
- {}
- { Chris Larson for FinderProgressBar }
- { Andrew Regan for ProgressBar CDEF }
- { Jim Stout for Jim's CDEF }
- { Harold Ekstrom for Slider CDEF }
-
- unit CelsiusCDEFStub;
-
-
- interface
-
-
- uses
- Windows, Palettes, CDEFUtils, CalculateBarBoundaryIntf;
-
-
- function CelsiusCDEF (inVarCode: SInt16;
- inControlHdl: ControlHandle;
- inMessage: ControlDefProcMessage;
- inParam: SInt32): SInt32;
-
-
- implementation
-
-
- const
- kInCelsiusControlPart = 50; { Value returned for the testCntl message }
-
- kBarberPoleVarCodeMask = $1; { Mask for obtaining the barber pole animation }
- kUseStdColorsVarCodeMask = $2; { Mask for drawing the bar with the standard dark gray-steel blue colors }
- kNeverDimControlVarCodeMask = $4; { Mask for drawing the bar always in the active state }
- kInsetBorderVarCodeMask = $8; { Mask for drawing an inset border around the bar }
-
- kDeviceLoopFlags = 0; { Flags passed to DeviceLoop }
-
- kMinimumColorDepth = 4; { Minimum depth for drawing in color, in bits per pixel }
- kMinimum3DDepth = 8; { Minimum depth for drawing the inset border, in bits per pixel }
-
- kBarberStripeWidth = 8; { Width of barber pole strips }
- kFPBFrameCount = 16; { Number of frames in the barber pole animation loop }
-
-
- type
- CelsiusCDEFDataHandle = ^CelsiusCDEFDataPtr;
- CelsiusCDEFDataPtr = ^CelsiusCDEFData;
- CelsiusCDEFData = record
- fDrawControlUPP: DeviceLoopDrawingUPP; { Pointer to drawing routine }
- fBlitControlUPP: DeviceLoopDrawingUPP; { Pointer to blitting routine }
- fOffscreenWorldPtr: GWorldPtr; { Pointer to offscreen world }
- fBlackPattern: Pattern; { Standard black pattern }
- fWhitePattern: Pattern; { Standard white pattern }
- fDitherPattern: Pattern; { 50% black-50% white pattern used for dimming }
- fControlOwnerForeColor: RGBColor; { Foreground color of the control's window }
- fControlOwnerContentColor: RGBColor; { Content color of the control's window }
- fBlackColor: RGBColor; { ($0000, $0000, $0000) black color }
- fWhiteColor: RGBColor; { ($FFFF, $FFFF, $FFFF) white color }
- fDarkGrayColor: RGBColor; { ($4000, $4000, $4000) dark gray ('done' part) color }
- fSteelBlueColor: RGBColor; { ($CCCC, $CCCC, $FFFF) steel blue ('to do' part) color }
- fDimGrayColor: RGBColor; { ($7FFF, $7FFF, $7FFF) gray color for dimming }
- fChiselGrayColor: RGBColor; { ($AAAA, $AAAA, $AAAA) chisel color as per develop 15 }
- fVariationCode: SInt16; { VarCode of current control (no other way of passing it to the draw routine) }
- fDepth: UInt16; { Saved depth state, for updating the offscreen world }
- fOffscreenDrawAvailable: Boolean; { True if we can draw in the offscreen world, false otherwise }
- end;
-
-
- { DrawInsetBorder }
- {}
- { Draws a 3D-like inset border in the specified rectangle if the content color of the control's window }
- { is the standard light gray ($EEEE, $EEEE, $EEEE), as defined in develop 15 }
- {}
- { Entry: inControlBounds = rectangle enclosing the control }
- { inWinBackColor = content color of the control's window }
- { inControlDataHdl = handle to border colors }
- procedure Draw3DInsetEffect (inControlBounds: Rect;
- inWinBackColor: RGBColor;
- inControlDataHdl: CelsiusCDEFDataHandle);
- begin
-
- { Draw the 3D border only if the window's content color is ($EEEE, $EEEE, $EEEE) }
- if EqualRGBColorComponents(inWinBackColor, kLightGrayRGBComp) then
- begin
- RGBBackColor(inWinBackColor);
-
- { Draw the top and left margins with the gray color and the bottom and right margins with the white }
- { color to achieve an 'inset' effect }
- RGBForeColor(inControlDataHdl^^.fWhiteColor);
- MoveTo(inControlBounds.left + 1, inControlBounds.bottom - 1);
- LineTo(inControlBounds.right - 1, inControlBounds.bottom - 1);
- LineTo(inControlBounds.right - 1, inControlBounds.top);
- RGBForeColor(inControlDataHdl^^.fChiselGrayColor);
- MoveTo(inControlBounds.left, inControlBounds.bottom - 1);
- LineTo(inControlBounds.left, inControlBounds.top);
- LineTo(inControlBounds.right - 1, inControlBounds.top);
- end;
- end;
-
-
- { DrawBarberPoleBar }
- {}
- { Draws the 'barber pole' animation effect }
- {}
- { Entry: inControlBounds = rectangle for drawing (prepared by the caller) }
- { inDarkColor = darker color for the diagonal stripes }
- { inLightColor = lighter color for the diagonal stripes }
- { inWinBackColor = background color of the control's window }
- { inControlHdl = handle to current control, to get the value }
- { inDepth = depth of current device }
- { inDitherContentFlag = TRUE if the bar content should be dithered, false otherwise }
- procedure DrawBarberPoleBar (inControlBounds: Rect;
- inDarkColor, inLightColor, inWinBackColor: RGBColor;
- inControlHdl: ControlHandle;
- inDepth: UInt16;
- inDitherContentFlag: Boolean);
- var
- i, height, frameNum: SInt16;
- begin
-
- { Set the pen size for the diagonal stripes }
- PenSize(kBarberStripeWidth, 1);
-
- { Setup the colors for drawing }
- if inDepth >= kMinimumColorDepth then
- begin
- RGBForeColor(inDarkColor);
- RGBBackColor(inLightColor);
- end
- else
- begin
- ForeColor(blackColor);
- BackColor(whiteColor);
- end;
-
- { Compute the horizontal starting point for drawing. Note that each drawing loop draws one }
- { stripe of each color (with gray drawn first). This starting point is set far enough to the }
- { left to make the first set of stripes drawn hit the lower left corner of the bar }
- height := inControlBounds.bottom - inControlBounds.top;
- frameNum := inControlHdl^^.contrlValue mod kFPBFrameCount;
- i := height + frameNum + (2 * kBarberStripeWidth) - 2;
- i := i div (2 * kBarberStripeWidth);
- i := inControlBounds.left - (i * 2 * kBarberStripeWidth) + frameNum;
-
- { Now back bias the starting location to account for the first increment }
- i := i - kBarberStripeWidth;
-
- { Until we would start drawing to the right of the bar, draw a pair of lines, slanting to the }
- { right, first of the two in the darker color, second in the lighter color }
- while i < inControlBounds.right do
- begin
- i := i + kBarberStripeWidth;
- PenMode(patCopy);
- MoveTo(i, inControlBounds.top);
- LineTo((i + height), (inControlBounds.bottom - 1));
- i := i + kBarberStripeWidth;
- PenMode(patBic);
- MoveTo(i, inControlBounds.top);
- LineTo((i + height), (inControlBounds.bottom - 1));
- end;
-
- { If this control should be dimmed, paint the control's rectangle with the dithering pattern }
- if inDitherContentFlag then
- begin
- if inDepth >= kMinimumColorDepth then
- RGBBackColor(inWinBackColor);
- PenMode(notPatBic);
- PenPat(CelsiusCDEFDataHandle(inControlHdl^^.contrlData)^^.fDitherPattern);
- PaintRect(inControlBounds);
- end;
- end;
-
-
- { DrawNormalBar }
- {}
- { Draws the normal done-to do progress bar using the supplied colors }
- {}
- { Entry: inControlBounds = rectangle for drawing (prepared by the caller) }
- { inDarkColor = darker color for the 'done' part }
- { inLightColor = lighter color for the 'to do' }
- { inWinBackColor = background color of the control's window }
- { inControlHdl = handle to current control, to get the value }
- { inDepth = depth of current device }
- { inDitherContentFlag = TRUE if the bar content should be dithered, false otherwise }
- procedure DrawNormalBar (inControlBounds: Rect;
- inDarkColor, inLightColor, inWinBackColor: RGBColor;
- inControlHdl: ControlHandle;
- inDepth: UInt16;
- inDitherContentFlag: Boolean);
- var
- savedBounds: Rect;
- savedRightBound: SInt16;
- begin
-
- { To properly dither the bar later, we must save here the current control's bounds, because }
- { they're altered by the following calls }
- if inDitherContentFlag then
- savedBounds := inControlBounds;
-
- { Save the current right border of the control's rect, because is modified by the CalculateBarBoundary call }
- savedRightBound := inControlBounds.right;
- inControlBounds.right := CalculateBarBoundary(inControlHdl, inControlBounds.left, inControlBounds.right);
-
- { Set up colors or pen pattern for the bar, then draw the bar }
- if inDepth >= kMinimumColorDepth then
- begin
- RGBForeColor(inDarkColor);
- RGBBackColor(inWinBackColor);
- end
- else
- PenPat(CelsiusCDEFDataHandle(inControlHdl^^.contrlData)^^.fBlackPattern);
- PaintRect(inControlBounds);
-
- { Now set up the rectangle to draw the 'empty' space not yet filled by the bar }
- inControlBounds.left := inControlBounds.right;
- inControlBounds.right := savedRightBound;
-
- { Set up colors or pen pattern for the 'empty' space, then draw the space }
- if inDepth >= kMinimumColorDepth then
- begin
- RGBForeColor(inLightColor);
- RGBBackColor(inWinBackColor);
- end
- else
- PenPat(CelsiusCDEFDataHandle(inControlHdl^^.contrlData)^^.fWhitePattern);
- PaintRect(inControlBounds);
-
- { Dither the content if we're asked, using the previously saved rect }
- if inDitherContentFlag then
- begin
- if inDepth >= kMinimumColorDepth then
- RGBBackColor(inWinBackColor);
- PenMode(notPatBic);
- PenPat(CelsiusCDEFDataHandle(inControlHdl^^.contrlData)^^.fDitherPattern);
- PaintRect(savedBounds);
- end;
- end;
-
-
- { DrawCelsiusControl }
- {}
- { DeviceLoop draw routine to draw the control in either the offscreen world or the control's port }
- {}
- { Entry: inDepth = depth of current device }
- { inDeviceFlags = flags describing current device properties (unused) }
- { inTargetDevice = handle to current device }
- { inUserData = container for the control's handle }
- procedure DrawCelsiusControl (inDepth: UInt16;
- inDeviceFlags: SInt16;
- inTargetDevice: GDHandle;
- inUserData: SInt32);
- var
- controlBounds: Rect;
- frameColor, darkColor, lightColor, winBackColor: RGBColor;
- controlHdl: ControlHandle;
- controlDataHdl: CelsiusCDEFDataHandle;
- auxCtlHdl: AuxCtlHandle;
- colorTabHdl: CCTabHandle;
- varCode: SInt16;
- hiliteState: UInt8;
- useStdColorsFlag, dimFlag: Boolean;
- begin
-
- { Get the control handle, the data handle and the control's hilite state }
- controlHdl := ControlHandle(inUserData);
- controlDataHdl := CelsiusCDEFDataHandle(controlHdl^^.contrlData);
- hiliteState := controlHdl^^.contrlHilite;
-
- { Get the variation code and the control's rect (in local coordinates relative to the control's window) }
- varCode := controlDataHdl^^.fVariationCode;
- controlBounds := controlHdl^^.contrlRect;
-
- { Set the drawing port to either the offscreen world, if available, or the control's port }
- if controlDataHdl^^.fOffscreenDrawAvailable then
- SetGWorld(controlDataHdl^^.fOffscreenWorldPtr, nil)
- else
- SetGWorld(CGrafPtr(controlHdl^^.contrlOwner), nil);
-
- { Always normalize the pen before drawing, to avoid unwanted side effects }
- PenNormal;
-
- { Dim the control only if the 'never dim' varCode is clear and if the control is inactive }
- dimFlag := (BAND(varCode, kNeverDimControlVarCodeMask) = 0) & (hiliteState = kControlInactivePart);
-
- { Must we use the standard dark gray / steel blue colors? }
- useStdColorsFlag := BAND(varCode, kUseStdColorsVarCodeMask) <> 0;
-
- { Set a well-known clipping; again, this helps avoiding surprises }
- ClipRect(controlBounds);
-
- { Check if the current device is deep enough for drawing our colors; if so, either fetch the colors from the control's }
- { data if we have to use the standard colors, or get them from the auxiliary control record. }
- { Then draw the inset border (if requested) and the frame }
- if inDepth >= kMinimumColorDepth then
- begin
-
- { Fetch the content color of the control's window that the BeginDraw routine stored for us }
- winBackColor := controlDataHdl^^.fControlOwnerContentColor;
-
- { Fetch the standard colors, stored at the control initialization in the control's data; also, pay attention to the }
- { control's hilite state and fetch the correct frame color }
- if useStdColorsFlag then
- begin
- if dimFlag then
- frameColor := controlDataHdl^^.fDimGrayColor
- else
- frameColor := controlDataHdl^^.fBlackColor;
- darkColor := controlDataHdl^^.fDarkGrayColor;
- lightColor := controlDataHdl^^.fSteelBlueColor;
- end
- else
- begin
-
- { Retrieve the control's auxiliary record; this strange 'if ... then ;' statement discards the function result (we }
- { don't care about it) }
- if GetAuxiliaryControlRecord(controlHdl, auxCtlHdl) then
- ;
-
- { Get the color table and lock it (necessary to avoid NIL dereferences) }
- colorTabHdl := auxCtlHdl^^.acCTable;
- HLock(Handle(colorTabHdl));
-
- { The control should be dimmed, so fetch the foreground color of the control's owner from the control's data and }
- { call GetGray to obtain the best gray for this device; note that if GetGray fails we use our standard dimGray color }
- if dimFlag then
- begin
- frameColor := controlDataHdl^^.fControlOwnerForeColor;
- if not GetGray(inTargetDevice, winBackColor, frameColor) then
- frameColor := controlDataHdl^^.fDimGrayColor;
- end
- else
-
- { The control shouldn't be dimmed, so fetch the frame color from the associated color table }
- frameColor := colorTabHdl^^.ctTable[cFrameColor].rgb;
-
- { The lighter color is the body color, and the darker color is the text color in the control's color table }
- lightColor := colorTabHdl^^.ctTable[cBodyColor].rgb;
- darkColor := colorTabHdl^^.ctTable[cTextColor].rgb;
-
- { Unlock the color table since we're done with it }
- HUnlock(Handle(colorTabHdl));
- end;
-
- { Determine if the control can feature the 'inset' effect, and call Draw3DInsetEffect }
- if (inDepth >= kMinimum3DDepth) and (BAND(varCode, kInsetBorderVarCodeMask) <> 0) and (not dimFlag) then
- Draw3DInsetEffect(controlBounds, winBackColor, controlDataHdl)
- else
-
- { The 'inset' effect cannot be displayed, so frame the control's rectangle with the content color of the control's }
- { window. This maintains consistency: the rectangle in which we draw the actual progress bar (or barber }
- { pole) should always keep the same size, regardless of the presence of the inset border. Letting the bar height }
- { float causes very unpleasant effects if the user changes the screen depth between 2 subsequent drawings. }
- begin
- RGBForeColor(winBackColor);
- RGBBackColor(winBackColor);
- FrameRect(controlBounds);
- end;
- end
- else
-
- { Black-&-white (or 4-colors) device: frame the control's rectangle with a white pattern. }
- begin
- PenPat(controlDataHdl^^.fWhitePattern);
- FrameRect(controlBounds);
- end;
-
- { Inset the control rect by 1 pixel to avoid overwriting the inset border, and for consistency in the case }
- { where the border is absent. See above for a more detailed explanation. }
- InsetRect(controlBounds, 1, 1);
-
- { Draw the control's frame. }
- if inDepth >= kMinimumColorDepth then
- begin
- RGBForeColor(frameColor);
- RGBBackColor(winBackColor);
- end
- else if inDepth < kMinimumColorDepth then
- if dimFlag then
- PenPat(controlDataHdl^^.fDitherPattern)
- else
- PenPat(controlDataHdl^^.fBlackPattern);
- FrameRect(controlBounds);
-
- { Inset the control rect by 1 pixel to avoid drawing over the frame; for maximum security, clip everything }
- { outside this newly inset rectangle }
- InsetRect(controlBounds, 1, 1);
- ClipRect(controlBounds);
-
- { Determine if we must draw the 'barber pole' animation or the regular bar and draw }
- if BAND(varCode, kBarberPoleVarCodeMask) <> 0 then
- DrawBarberPoleBar(controlBounds, darkColor, lightColor, winBackColor, controlHdl, inDepth, dimFlag)
- else
- DrawNormalBar(controlBounds, darkColor, lightColor, winBackColor, controlHdl, inDepth, dimFlag);
- end;
-
-
- { BlitCelsiusControl }
- {}
- { DeviceLoop draw routine to copy the control drawing from the offscreen world to the control's port }
- {}
- { Entry: inDepth = depth of current device }
- { inDeviceFlags = flags describing current device properties (unused) }
- { inTargetDevice = handle to current device (unused) }
- { inUserData = container for the control's handle }
- procedure BlitCelsiusControl (inDepth: UInt16;
- inDeviceFlags: SInt16;
- inTargetDevice: GDHandle;
- inUserData: SInt32);
- var
- controlBounds: Rect;
- controlDataHdl: CelsiusCDEFDataHandle;
- offWorldPtr: GWorldPtr;
- controlPort: CGrafPtr;
- begin
-
- { Get the control's data, the control's port and the control's rect }
- controlDataHdl := CelsiusCDEFDataHandle(ControlHandle(inUserData)^^.contrlData);
- controlPort := CGrafPtr(ControlHandle(inUserData)^^.contrlOwner);
- controlBounds := ControlHandle(inUserData)^^.contrlRect;
-
- { Proceed only if the offscreen world is available }
- if controlDataHdl^^.fOffscreenDrawAvailable then
- begin
- offWorldPtr := controlDataHdl^^.fOffscreenWorldPtr;
-
- { The offscreen world's pixMap has already been locked by the caller, so we set the port }
- { to the control's owner, set the foreground color to black and background color to white to avoid colorization }
- { by CopyBits and start blitting }
- SetGWorld(controlPort, nil);
- RGBForeColor(controlDataHdl^^.fBlackColor);
- RGBBackColor(controlDataHdl^^.fWhiteColor);
- CopyBits(GrafPtr(offWorldPtr)^.portBits, GrafPtr(controlPort)^.portBits, offWorldPtr^.portRect, controlBounds, srcCopy, nil);
- end;
- end;
-
-
- { BeginDraw }
- {}
- { Responds to the drawCntl message by saving the current port, color, ecc. settings, by activating ours and }
- { by calling DeviceLoop to draw the control }
- {}
- { Entry: inControlHdl = handle to current control }
- { inVarCode = variation code of current control }
- procedure BeginDraw (inControlHdl: ControlHandle;
- inVarCode: SInt16);
- var
- controlBounds: Rect;
- saveForeColor, saveBackColor: RGBColor;
- savePen: PenState;
- saveClip, controlRgn, drawingRgn: RgnHandle;
- auxWinHdl: AuxWinHandle;
- colorTabHdl: CTabHandle;
- savePort, controlPort: CGrafPtr;
- saveDevice: GDHandle;
- controlDataHdl: CelsiusCDEFDataHandle;
- ignoredFlags: GWorldFlags;
- currDepth: UInt16;
- offscreenDrawFlag: Boolean;
- begin
-
- { Exit immediately if our custom data isn't available }
- controlDataHdl := CelsiusCDEFDataHandle(inControlHdl^^.contrlData);
- if controlDataHdl = nil then
- Exit(BeginDraw);
-
- { Save current settings (port, clipping, colors, ecc.) }
- GetGWorld(savePort, saveDevice);
- controlPort := CGrafPtr(inControlHdl^^.contrlOwner);
- SetGWorld(controlPort, nil);
- GetForeColor(saveForeColor);
- GetBackColor(saveBackColor);
- GetPenState(savePen);
-
- { Now the current port is the control's port, and we intersect its clipping region with our control rectangle; if this }
- { intersection is empty then exit without drawing anything. This indeed means that all our drawing would be clipped out }
-
- { Get the visRgn of the control's window, to pass it to DeviceLoop later }
- drawingRgn := controlPort^.visRgn;
-
- controlBounds := inControlHdl^^.contrlRect;
-
- { Allocate 2 regions for our purposes }
- controlRgn := NewRgn;
- saveClip := NewRgn;
-
- if (saveClip <> nil) and (controlRgn <> nil) then
- begin
- GetClip(saveClip);
- RectRgn(controlRgn, controlBounds);
-
- { Intersect the current clip region with the control's rectangle: if this intersection is empty then dispose of our }
- { regions and exit }
- SectRgn(saveClip, controlRgn, controlRgn);
- if EmptyRgn(controlRgn) then
- begin
- DisposeRgn(saveClip);
- DisposeRgn(controlRgn);
- SetGWorld(savePort, saveDevice);
- Exit(BeginDraw);
- end
- else
-
- { All right: set the clip region to the previously calculated intersection and go ahead }
- SetClip(controlRgn);
- end
- else
-
- { Bad, bad: we don't have enough memory to allocate 2 regions, so exit }
- begin
- SetGWorld(savePort, saveDevice);
- Exit(BeginDraw);
- end;
-
- { Lock our data to avoid problems }
- HLock(Handle(controlDataHdl));
-
- { Drawing with the 'cctb' colors requires informations about the foreground color of the control's window, so }
- { store it into our data to avoid another couple of Get/SetGWorld calls later. }
- { Possible improvement: storing this color is needed only if dimFlag = true, so we could calculate dimFlag in this }
- { routine rather than in DrawCelsiusControl }
- if BAND(inVarCode, kUseStdColorsVarCodeMask) = 0 then
- controlDataHdl^^.fControlOwnerForeColor := saveForeColor;
-
- { Store into our data the content color of the control's window, because we will need it to frame the }
- { control's bounds when not drawing the inset border }
- if GetAuxWin(WindowPtr(controlPort), auxWinHdl) then
- ;
- colorTabHdl := auxWinHdl^^.awCTable;
- HLock(Handle(colorTabHdl));
- controlDataHdl^^.fControlOwnerContentColor := colorTabHdl^^.ctTable[wContentColor].rgb;
- HUnlock(Handle(colorTabHdl));
-
- { If the offscreen world is available, update it if the depth changed between the last drawing and call }
- { DeviceLoop 1) first to draw into it and 2) to blit from it to the control's port; otherwise call DeviceLoop }
- { to do a simple draw in the control's window }
- offscreenDrawFlag := (controlDataHdl^^.fOffscreenWorldPtr <> nil) & LockPixels(GetGWorldPixMap(controlDataHdl^^.fOffscreenWorldPtr));
-
- { Signal the availability of the offscreen world to the actual draw procedure }
- controlDataHdl^^.fOffscreenDrawAvailable := offscreenDrawFlag;
-
- if offscreenDrawFlag then
- begin
-
- { Update our offscreen world if the depth has changed, and store the new depth}
- currDepth := GetControlPortDepth(inControlHdl);
- if controlDataHdl^^.fDepth <> currDepth then
- begin
- ignoredFlags := UpdateGWorld(controlDataHdl^^.fOffscreenWorldPtr, kDeepestDeviceDepth, controlDataHdl^^.fOffscreenWorldPtr^.portRect, nil, nil, kOffWorldFlags);
- controlDataHdl^^.fDepth := currDepth;
- end;
-
- { Draw the control in the offscreen world }
- DeviceLoop(drawingRgn, controlDataHdl^^.fDrawControlUPP, SInt32(inControlHdl), kDeviceLoopFlags);
-
- { Copy the newly drawn control from the offscreen world to the control's port }
- DeviceLoop(drawingRgn, controlDataHdl^^.fBlitControlUPP, SInt32(inControlHdl), kDeviceLoopFlags);
- UnlockPixels(GetGWorldPixMap(controlDataHdl^^.fOffscreenWorldPtr));
- end
- else
-
- { The offscreen world is not accessible, so we draw in the control's port anyway }
- DeviceLoop(drawingRgn, controlDataHdl^^.fDrawControlUPP, SInt32(inControlHdl), kDeviceLoopFlags);
-
- { Restore the previous settings, unlock our data and exit }
- SetClip(saveClip);
- if saveClip <> nil then
- DisposeRgn(saveClip);
- if controlRgn <> nil then
- DisposeRgn(controlRgn);
- RGBForeColor(saveForeColor);
- RGBBackColor(saveBackColor);
- SetPenState(savePen);
- SetGWorld(savePort, saveDevice);
- HUnlock(Handle(controlDataHdl));
- end;
-
-
- { InitControlData }
- {}
- { Initializes the control private data, filling it with the UPPs, the patterns, ecc. }
- {}
- { Entry: inControlHdl = handle to current control }
- { inVarCode = variation code of current control }
- procedure InitControlData (inControlHdl: ControlHandle;
- inVarCode: SInt16);
- var
- theDataHdl: CelsiusCDEFDataHandle;
- drawUPP, blitUPP: DeviceLoopDrawingUPP;
- offWorldPtr: GWorldPtr;
- err: OSErr;
- begin
- theDataHdl := nil;
-
- { Allocate memory for the control's data }
- theDataHdl := CelsiusCDEFDataHandle(NewHandleClear(SizeOf(CelsiusCDEFData)));
- err := MemError;
-
- { If the allocation was successful then fill in the fields, else punt }
- if (err = noErr) and (theDataHdl <> nil) then
- begin
-
- { Lock the data to avoid problems (the following calls should move memory) }
- HLock(Handle(theDataHdl));
-
- { Store the draw and blit procedures }
- drawUPP := NewDeviceLoopDrawingProc(@DrawCelsiusControl);
- theDataHdl^^.fDrawControlUPP := drawUPP;
- blitUPP := NewDeviceLoopDrawingProc(@BlitCelsiusControl);
- theDataHdl^^.fBlitControlUPP := blitUPP;
-
- { Store the offscreen graphics world }
- err := CreateControlOffscreenWorld(inControlHdl, offWorldPtr);
- if err = noErr then
- theDataHdl^^.fOffscreenWorldPtr := offWorldPtr;
-
- { Store the patterns; getting them via Resource Mgr. calls helps insulating us from using the evil }
- { QuickDraw globals }
- GetIndPattern(theDataHdl^^.fBlackPattern, sysPatListID, kBlackPatternIndex);
- GetIndPattern(theDataHdl^^.fWhitePattern, sysPatListID, kWhitePatternIndex);
- GetIndPattern(theDataHdl^^.fDitherPattern, sysPatListID, kGrayPatternIndex);
-
- { Store the colors; note that the foreground and background colors of the control's window are stored }
- { by the BeginDraw procedure }
- SetRGBColor(theDataHdl^^.fBlackColor, kBlackColorRGBComp, kBlackColorRGBComp, kBlackColorRGBComp);
- SetRGBColor(theDataHdl^^.fWhiteColor, kWhiteColorRGBComp, kWhiteColorRGBComp, kWhiteColorRGBComp);
-
- if BAND(inVarCode, kUseStdColorsVarCodeMask) <> 0 then
- begin
- SetRGBColor(theDataHdl^^.fDarkGrayColor, kDarkGrayColorRGBComp, kDarkGrayColorRGBComp, kDarkGrayColorRGBComp);
- SetRGBColor(theDataHdl^^.fSteelBlueColor, kSteelBlueColorRGComp, kSteelBlueColorRGComp, kSteelBlueColorBComp);
- SetRGBColor(theDataHdl^^.fDimGrayColor, kDimGrayColorRGBComp, kDimGrayColorRGBComp, kDimGrayColorRGBComp);
- end;
-
- { This color is calculated only if the variation code specifies that we should draw the inset effect }
- if BAND(inVarCode, kInsetBorderVarCodeMask) <> 0 then
- SetRGBColor(theDataHdl^^.fChiselGrayColor, kChiselGrayColorRGBComp, kChiselGrayColorRGBComp, kChiselGrayColorRGBComp);
-
- { Store the variation code of the current control; unfortunately, we don't have any other way of }
- { passing it to the drawing routine }
- theDataHdl^^.fVariationCode := inVarCode;
-
- { Store the depth of the control's port }
- theDataHdl^^.fDepth := GetControlPortDepth(inControlHdl);
-
- { Unlock data }
- HUnlock(Handle(theDataHdl));
- end;
-
- { Store the initialized data in the contrlData field; note that even the NIL handle of a unsuccessful }
- { allocation is stored, because is checked by the draw routine that exits if encounters such a handle }
- inControlHdl^^.contrlData := Handle(theDataHdl);
- end;
-
-
- { DisposeControlData }
- {}
- { Disposes of all the private data created at initialization time }
- {}
- { Entry: inControlHdl = handle to control }
- procedure DisposeControlData (inControlHdl: ControlHandle);
- var
- theDataHdl: CelsiusCDEFDataHandle;
- begin
- theDataHdl := CelsiusCDEFDataHandle(inControlHdl^^.contrlData);
-
- { Go ahead only if our data is not NIL }
- if theDataHdl <> nil then
- begin
-
- { Dispose of the draw and blit UPPs }
- DisposeRoutineDescriptor(theDataHdl^^.fDrawControlUPP);
- DisposeRoutineDescriptor(theDataHdl^^.fBlitControlUPP);
-
- { Dispose of the offscreen graphics world }
- if theDataHdl^^.fOffscreenWorldPtr <> nil then
- DisposeGWorld(theDataHdl^^.fOffscreenWorldPtr);
-
- { Finally, dispose of the data itself and set it to NIL to avoid multiple disposal }
- DisposeHandle(Handle(theDataHdl));
- theDataHdl := nil;
- end;
- end;
-
-
- { CelsiusCDEF }
- {}
- { Main entry point for the progress bar control definition function. Dispatches the messages to the }
- { appropriate subroutines }
- {}
- { Entry: inVarCode = variation of control to handle }
- { inControlHdl = handle to ControlRecord describing the current control }
- { inMessage = identifies the subfunction requested }
- { inParam = variable value, depending on inMessage }
- { Exit: function result = variable value, depending on inMessage }
- function CelsiusCDEF (inVarCode: SInt16;
- inControlHdl: ControlHandle;
- inMessage: ControlDefProcMessage;
- inParam: SInt32): SInt32;
- var
- returnValue: SInt32;
- ctrlRecState: SignedByte;
- begin
-
- { Don't waste time if we're called with a NIL control handle (this should not happen anyway) }
- if inControlHdl = nil then
- Exit(CelsiusCDEF);
-
- { Lock down our control for the whole drawing time }
- ctrlRecState := HGetState(Handle(inControlHdl));
- HLock(Handle(inControlHdl));
-
- { Return 0 as default from our defproc (we don't have indicators) }
- returnValue := 0;
-
- { Dispatch the current message to the appropriate subroutine }
- case inMessage of
-
- { Draw the control (only if it's visible) }
- drawCntl:
- if inControlHdl^^.contrlVis <> 0 then
- BeginDraw(inControlHdl, inVarCode);
-
- { Initializes the control's data }
- initCntl:
- InitControlData(inControlHdl, inVarCode);
-
- { Disposes of the control's data }
- dispCntl:
- DisposeControlData(inControlHdl);
-
- { Return kInProgressControlPart if the click is inside the control's rect }
- testCntl:
- if PtInRect(Point(inParam), inControlHdl^^.contrlRect) then
- returnValue := kInCelsiusControlPart;
-
- { Return the control's rectangle as a region, in 32-bit addressing mode }
- calcCntlRgn:
- RectRgn(RgnHandle(inParam), inControlHdl^^.contrlRect);
-
- { Return the control's rectangle as a region, in 24-bit addressing mode; note that IM-Toolbox Essentials }
- { p. 5-112 says that we should clear the high-order bit before calculating the region, but does not specify }
- { that the region handle we return must be confined to the low 3 bytes of inParam }
- calcCRgns:
- if BAND(inParam, kClearHighByteMask) = 0 then
- RectRgn(RgnHandle(StripAddress(inParam)), inControlHdl^^.contrlRect);
-
- otherwise
- ;
- end;
-
- { Unlock the control and return }
- HSetState(Handle(inControlHdl), ctrlRecState);
- CelsiusCDEF := returnValue;
- end;
-
-
- end.